package com.tiglle.lettuce.controller;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
public class TestController {

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 一.测试redisTemplate
     */
    @GetMapping("test")
    public String test(){
        redisTemplate.opsForValue().set("aaa","bbb");
        Object aaa = redisTemplate.opsForValue().get("aaa");
        System.out.println(aaa.toString());
        return "success";
    }

    /**
     * 二.redis的事务
     * 1.multi：开启一个事务
     * 按先后顺序添加命令进事务列队 添加命令时出现错误，exec时整个列队命令都不会执行
     * 2.exec：执行事务列队中的命令 执行命令时出现错误，只有报错的命令不会执行，其他命令依然执行
     * 先添加的先执行，后添加的后执行
     * 3.discard：取消事务，放弃事务列队的命令
     * 下面有乐观锁watch和unwatch
     *
     * redis事务特性：
     * 1.隔离性：事务列队执行时，不会被其他客户端请求打断
     * 2.无隔离级别
     * 3.无原子性：执行时，一个指令出错，不会回滚正确执行的指令数据
     */
    @GetMapping("trans")
    public String trans(){
        //redisTemplate的事务不像jedis，需要实现SessionCallback接口
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                //开启事务
                operations.multi();
                //添加命令进事务列队
                operations.opsForValue().set("tiglle1","111");
                operations.opsForValue().increment("tiglle2");
                //执行事务
                List exec = operations.exec();
                System.out.println(exec);
                //取消事务和命令的执行
                //operations.discard();
                return null;
            }
        });
        return "success";
    }

    /**
     * 三.乐观锁watch
     * 1.watch keys.....：监视一个或多个key，key值被改变后取消监听，一次性的
     * 跟事务一起用
     * 当一个key被监听后，添加到事务列队中后，在执行exec时，key值之前被改变过，那么会执行失败，事务会被打断，列队中的命令都不会执行
     * 2.unwatch：取消watch对所有key的监视
     */
    @GetMapping("lock")
    public String lock(){
        //redisTemplate的事务不像jedis，需要实现SessionCallback接口
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                //开启监听
                operations.watch("tiglle2");
                //开启事务
                operations.multi();
                //添加命令进事务列队
                operations.opsForValue().set("tiglle1","aaa");
                operations.opsForValue().increment("tiglle2");
                operations.opsForValue().set("tiglle3","bbb");
                //这里用redisTemplate也会被加入事务列队中
                redisTemplate.opsForValue().set("tiglle4","ddd");
                //手动在redis-cli中修改tiglle2的值，然后在执行exce
                //执行事务，会失败，返回结果为空数组
                List exec = operations.exec();
                System.out.println(exec);
                //取消事务和命令的执行
                //operations.discard();
                return null;
            }
        });
        return "success";
    }

}
